package io.renren.utils.wx;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;


@Component
@Data
public class WxAccessTokenUtils {

    private static final Logger logger = LoggerFactory.getLogger(WxAccessTokenUtils.class);

    private String accessToken;

    private String refreshToken;

    @Autowired
    private WxConfig wxConfig;

    @Autowired
    private RestTemplate restTemplate;

    /**
     * WX 网页授权的方法
     *
     * @param code 前端网页进行第三方授权成功后获得的用户 code
     * @return 带有用户信息的token
     */
    public WxUser getAccessTokenAndOpenId(String code) {
        String codeAccessToken = wxConfig.getCodeAccessToken();
        String url = String.format(codeAccessToken, wxConfig.getAppId(), wxConfig.getAppSecret(), code);
        ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class);
        String body = forEntity.getBody();
        logger.info("微信授权请求返回body为:{}", body);
        JSONObject jsonObject = JSON.parseObject(body);

        String accessToken = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid");

        if (!StringUtils.hasText(accessToken) && !StringUtils.hasText(openid)) {
            checkErrorInfo(jsonObject);
            return null;
        }


        // 校验 accessToken 和 openId
        if (!isEffective(accessToken, openid)) {
            logger.info("检验access_token 和 openid失败,token或openID无效");
            return null;
        }

        synchronized (WxAccessTokenUtils.class) {
            this.accessToken = accessToken;
            this.refreshToken = jsonObject.getString("refresh_token");
            return getUserInfo(openid);
        }
    }

    /**
     * 对 WX 授权成功返回的 access token 和 openID 进行校验,判断是否有效
     *
     * @param accessToken 微信网页授权请求访问的令牌
     * @param openid      用户openId
     * @return true -> 有效  false -> 无效
     */
    private boolean isEffective(String accessToken, String openid) {
        String wxTokenCheckUrl = wxConfig.getWxtokencheck();
        String url = String.format(wxTokenCheckUrl, accessToken, openid);
        ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class);
        String body = forEntity.getBody();
        JSONObject jsonObject = JSON.parseObject(body);
        if ("ok".equals(jsonObject.get("errmsg"))) {
            return true;
        }
        return false;
    }

    /**
     * 获取 WX 用户信息的方法
     * 根据 WX 用户的 openid 查询到用户的信息 放入 tokenMap 中
     */
    private WxUser getUserInfo(String openId) {
        String userInfoUrl = wxConfig.getUserInfoUrl();
        userInfoUrl = userInfoUrl + "access_token=" + accessToken + "&openid=" + openId + "&lang=zh_CN";
        ResponseEntity<String> forEntity = restTemplate.getForEntity(userInfoUrl, String.class);
        String body = forEntity.getBody();
        try {
            body = new String(body.getBytes(StandardCharsets.ISO_8859_1), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            logger.error("wx获取用户信息时,编码转换异常");
            logger.error(e.getMessage(), e);
            return null;
        }
        JSONObject jsonObject = JSON.parseObject(body);
        logger.info("查询微信用户信息为:{}", jsonObject.toJSONString());
        WxUser wxUser = new WxUser();
        wxUser.setNickname(jsonObject.getString("nickname"));
        wxUser.setSex(jsonObject.getString("sex"));
        wxUser.setProvince(jsonObject.getString("province"));
        wxUser.setCity(jsonObject.getString("city"));
        wxUser.setCountry(jsonObject.getString("country"));
        wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));

        logger.info("返回的微信用户对象 {}", wxUser);
        return wxUser;
    }


    /**
     * 请求异常原因
     *
     * @param jsonObject
     */
    private void checkErrorInfo(JSONObject jsonObject) {
        Integer errcode = (Integer) jsonObject.get("errcode");
        switch (errcode) {
            case -1:
                logger.error("请求微信AccessToken失败原因为:微信系统繁忙，此时请开发者稍候再试");
                break;
            case 40001:
                logger.error("请求微信AccessToken失败原因为:AppSecret错误或者AppSecret不属于这个公众号，请开发者确认AppSecret的正确性");
                break;
            case 40029:
                logger.error("请求微信AccessToken失败原因为:code码有误");
                break;
            case 40013:
                logger.error("请求微信AccessToken失败原因为:AppId有误请检查appid");
                break;
            case 40002:
                logger.error("请求微信AccessToken失败原因为:请确保grant_type字段值为client_credential");
                break;
            case 40164:
                logger.error("请求微信AccessToken失败原因为:调用接口的IP地址不在白名单中，请在接口IP白名单中进行设置。（小程序及小游戏调用不要求IP地址在白名单内。");
                break;
            case 89503:
                logger.error("请求微信AccessToken失败原因为:此IP调用需要管理员确认,请联系管理员");
                break;
            case 89501:
                logger.error("请求微信AccessToken失败原因为:此IP正在等待管理员确认,请联系管理员");
                break;
            case 89506:
                logger.error("请求微信AccessToken失败原因为:24小时内该IP被管理员拒绝调用两次，24小时内不可再使用该IP调用");
                break;
            case 89507:
                logger.error("请求微信AccessToken失败原因为:1小时内该IP被管理员拒绝调用一次，1小时内不可再使用该IP调用");
                break;
            default:
                logger.error("请求微信AccessToken失败");
        }
    }


}
